package com.github.h4de5ing.kmp.rtk

import com.fazecast.jSerialComm.SerialPort
import java.io.File


class RTKApp(private val log: (String) -> Unit, private val onChange: (GGA) -> Unit = {}) {
    private val initCommand = arrayOf(
        "47 50 47 47 41 20 31 0D 0A",//GPGGA 0.1 //从天线计算的卫星定位信息，0.1代表10HZ
        "47 50 47 4C 4C 20 31 0D 0A",//GPGLL 0.1 //从天线计算的地理位置信息
        "47 50 47 4E 53 20 31 0D 0A",//GPGNS 0.1 //从天线计算的定位数据输出
        "47 50 47 53 41 20 31 0D 0A",//GPGSA 0.1 //从天线参与定位解算的卫星信息
        "47 50 47 53 56 20 31 0D 0A",//GPGSV 0.1 //从天线的可视卫星信息输出
        "47 50 52 4D 43 20 31 0D 0A",//GPRMC 0.1 //从天线的卫星定位信息
        "47 50 56 54 47 20 31 0D 0A",//GPVTG 1 //从天线的地面航向和速度信息
        "47 50 47 52 53 20 31 0D 0A",//GPGRS 1 //从天线定位解算的卫星残差
        "47 50 47 53 54 20 31 0D 0A",//GPGST 1 //从天线计算的伪距观测误差信息
        "47 50 48 50 52 20 31 0D 0A",//GPHPR 1 //姿态参数
        "73 61 76 65 63 6F 6E 66 69 67 0D 0A"//saveconfig
    )
    private val cmd: Array<String> = arrayOf("unlogall \r\n ", "log gpgga ontime 1\r\n")

    private var sp: SerialPort? = null
    private var isOpen = false //gps 串口是否打开成功

    private var isRTK = false //rtk 是否打开成功
    private var isRadio = false //radio 是否打开成功
    private var radioApp: RadioApp? = null //电台应用
    private var socket: SocketClient? = null
    fun start(
        host: String,
        port: Int,
        mountPoint: String,
        username: String,
        password: String,
        isRadio: Boolean,
        isRTK: Boolean,
        configFinish: () -> Unit,
    ) {
        this.isRTK = isRTK
        this.isRadio = isRadio
        if ((isRadio && !isRTK) || !isRadio) {
            socket = SocketClient()
            socket?.start(
                host,
                port,
                mountPoint,
                username,
                password
            ) { data, length -> setNetData(data.copyOfRange(0, length)) }
        }
        if (isRadio) {
            radioApp = RadioApp()
            radioApp?.start(configFinish = configFinish, log = log) {
                if (isRTK) toUart(it) else toNet(it)
            }
        }
        if (!isRadio || isRTK) {
            try {
                sp = SerialPort.getCommPort("ttysWK2")
                isOpen = sp?.openPort() ?: false
                log("GPS串口打开${sp?.systemPortName} ${if (isOpen) "成功" else "失败"}")
                sp?.setComPortParameters(115200, 8, 1, 0)
                sp?.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 1000, 0)
                Thread {
                    println("Thread------------------------gps uart")
                    initCommand.forEach {
                        val send = toByteArray(it)
                        sp?.writeBytes(send, send.size)
                    }
                    cmd.forEach {
                        val send = it.toByteArray()
                        sp?.writeBytes(send, send.size)
                        Thread.sleep(1000)
                    }
                    val readBuffer = ByteArray(2048)
                    val gpsList = File("gps2.txt").readLines().toMutableList()
                    var index = 0
                    while (true) {
                        try {
                            val length = sp?.readBytes(readBuffer, readBuffer.size) ?: 0
                            if (length > 0) {
                                print("${String(readBuffer, 0, length)}\r")
                                onNmea(readBuffer.copyOfRange(0, length))
                            }
//                            if (index >= gpsList.size) index = 0
//                            val gpsLog = gpsList[index++]
//                            log(gpsLog)
//                            onNmea(gpsLog.toByteArray())
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }
                        Thread.sleep(100)
                    }
                }.start()
            } catch (e: Exception) {
                log("gps 串口异常:${e.message}")
                e.printStackTrace()
            }
        }
    }

    private fun toUart(byteArray: ByteArray) {
        sp?.writeBytes(byteArray, byteArray.size)
    }

    private fun onNmea(data: ByteArray) {
        try {
            val str = String(data)
            if (str.contains("GGA")) {
                val items = str.split(",").dropLastWhile { it.isEmpty() }.toTypedArray()
                if (items.size > 13) {
                    val gga = GGA(
                        time = items[1],
                        latitude = "${dmToD(items[2].toDouble())}",
                        longitude = "${dmToD(items[4].toDouble())}",
                        state = items[6],
                        satellites = items[7],
                        accuracy = items[8],
                        altitude = items[9]
                    )
                    onGGA(data)
                    onChange(gga)
                }
            }
        } catch (e: Exception) {
            //e.printStackTrace()
        }
    }

    private fun dmToD(data: Double): Double {
        val value = (data / 100).toInt()
        val result = value + (data - value * 100) / 60
        return result
    }

    private fun onGGA(data: ByteArray) {
        if ((isRadio && isRTK)) changUIString = data
        socket?.write(data)
    }

    private fun toNet(data: ByteArray) = socket?.write(data)

    private fun setNetData(data: ByteArray) {
        if (isRadio && !isRTK)
            changUIString = data
        sp?.writeBytes(data, data.size)
    }
}